﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Commons;
using Core;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Model;
using Newtonsoft.Json;
using NLog;
using WebApp.Model;
using WebApp.Models;
using System.Security.Cryptography;
using Core.Factory;
using System.Xml.Serialization;
using System.IO;

namespace WebApp.ApiControllers
{
    /// <summary>
    /// 支付管理
    /// </summary>
    //[Produces("application/json")]
    [Route("api/[controller]/[action]")]
    public class PaymentController : Controller
    {
        private readonly IBaseService _baseService;
        private readonly IUserService _userService;
        private readonly Logger log = LogManager.GetCurrentClassLogger();
        /// <summary>
        /// 微信预支付接口地址
        /// </summary>
        private string _buyurl = MyConfigurationSection.GetSite("WXBuyUrl");
        /// <summary>
        /// 小程序appid
        /// </summary>
        private string _appId = MyConfigurationSection.GetSite("AppID");
        /// <summary>
        /// 商户id
        /// </summary>
        private string _mchId = MyConfigurationSection.GetSite("MchId");
        /// <summary>
        /// 终端ip
        /// </summary>
        private string _spbillIP = MyConfigurationSection.GetSite("SpbillIP");
        /// <summary>
        /// 通知地址
        /// </summary>
        private string _notifyUrl = MyConfigurationSection.GetSite("NotifyUrl");
        /// <summary>
        /// 密钥设置
        /// </summary>
        private string _key = MyConfigurationSection.GetSite("MchKey");

        /// <summary>
        /// 
        /// </summary>
        /// <param name="baseService"></param>
        /// <param name="userService"></param>
        public PaymentController(IBaseService baseService, IUserService userService)
        {
            _baseService = baseService;
            _userService = userService;
        }
        /// <summary>
        /// 添加购买记录
        /// </summary>
        /// <param name="t_Buy"></param>
        /// <returns></returns>
        [HttpPost]
        public ResultModel Post(T_BuyRecord t_Buy)
        {
            ResultModel result = new ResultModel();
            try
            {
                t_Buy.BuyNum = DateTime.Now.ToString("yyyyMMddHHmmssffffff");
                t_Buy.CreateDate = DateTime.Now;
                t_Buy.State = "待支付";
                var vip = _baseService.GetModel<T_VipModel>(i => i.Code == t_Buy.VipModel);
                if (vip == null)
                {
                    result.msg = "未找到相关购买模式";
                    result.code = "500";
                    log.Error("未找到相关购买模式");
                    return result;
                }
                t_Buy.Money = vip.Money;//元
                var re = _userService.NewBuy(t_Buy);

                if (re != null)
                {
                    Random random = new Random();
                    int nonce = random.Next(0, 9999);
                    BuyModel buyModel = new BuyModel();

                    buyModel.appid = _appId;
                    buyModel.mch_id = _mchId;
                    buyModel.nonce_str = nonce.ToString();
                    buyModel.body = "活动助手-高级版购买";
                    buyModel.out_trade_no = re.BuyNum;
                    buyModel.total_fee = (int)(re.Money * 100);//分
                    buyModel.spbill_create_ip = _spbillIP;
                    buyModel.notify_url = _notifyUrl;
                    buyModel.trade_type = "JSAPI";
                    buyModel.openid = _baseService.GetModel<T_User>(i => i.Id == re.UserId).WxOpenId;
                    //放在最后
                    buyModel.sign = GetSign(buyModel);
                    XmlSerializer xmlSerializer = new XmlSerializer(buyModel.GetType(), "xml");
                    MemoryStream ms = new MemoryStream();
                    xmlSerializer.Serialize(ms, buyModel);
                    ms.Position = 0;
                    StreamReader sr = new StreamReader(ms);
                    var ss = sr.ReadToEnd();
                    sr.Close();
                    ms.Close();

                    HttpClient client = new HttpClient();
                    HttpContent httpContent = new StringContent(ss.Replace("BuyModel", "xml"));
                    httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/xml");

                    HttpResponseMessage response = client.PostAsync(_buyurl, httpContent).Result;
                    string responseResult = response.Content.ReadAsStringAsync().Result;
                    client.Dispose();
                    ReBuyModel reBuy = null;
                    using (StringReader srs = new StringReader(responseResult.Replace("xml", "ReBuyModel")))
                    {
                        XmlSerializer xmldes = new XmlSerializer(typeof(ReBuyModel));
                        reBuy = xmldes.Deserialize(srs) as ReBuyModel;
                    }
                    //ReBuyModel reBuy = JsonConvert.DeserializeObject<ReBuyModel>(responseResult);
                    if (reBuy.return_code == "SUCCESS")
                    {
                        if (reBuy.result_code == "SUCCESS")
                        {
                            result.data = new { reBuy.prepay_id, payId = re.Id };
                            result.msg = "预付订单生成成功";
                            result.type = MsgType.success.ToString();
                            result.result = (int)MsgType.success;
                            result.code = "200";
                        }
                        else
                        {
                            result.msg = "预付失败";
                            log.Error("预付失败:" + re.Id);
                            log.Error(reBuy.err_code + ":" + reBuy.err_code_des);
                        }
                    }
                    else
                    {
                        result.msg = "签名失败";
                        result.code = "500";
                        log.Error("签名失败:" + re.Id);
                    }
                }
                else
                {
                    result.msg = "购买记录生成失败";
                    result.code = "500";
                    log.Error("购买记录生成失败:" + re.Id);
                }

            }
            catch (Exception ex)
            {
                result.msg = ex.Message;
                result.code = "500";
                log.Error(ex, ex.Message);
            }
            return result;
        }
        /// <summary>
        /// 购买记录
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ResultModel Get()
        {
            ResultModel result = new ResultModel();
            try
            {
                var list = _baseService.GetList<T_BuyRecord>(i => true, i => i.Desc(o => o.CreateDate));
                result.result = (int)MsgType.success;
                result.type = MsgType.success.ToString();
                result.code = "200";
                result.data = list;
                result.msg = "获取数据成功";
            }
            catch (Exception ex)
            {
                result.msg = ex.Message;
                result.code = "500";
                log.Error(ex, ex.Message);
            }
            return result;
        }
        /// <summary>
        /// 签名算法
        /// </summary>
        /// <param name="buyModel"></param>
        /// <returns></returns>
        private string GetSign(BuyModel buyModel)
        {
            Dictionary<string, string> dics = new Dictionary<string, string>();

            var properties = typeof(BuyModel).GetProperties();
            foreach (System.Reflection.PropertyInfo info in properties)
            {
                string name = info.Name;
                var value = buyModel.GetType().GetProperty(name).GetValue(buyModel, null);
                if (value != null)
                {
                    if (!string.IsNullOrWhiteSpace(value.ToString()))
                    {
                        dics.Add(name, value.ToString());
                    }
                }
            }

            var reDics = dics.OrderBy(i => i.Key);
            string strA = "";
            foreach (var item in reDics)
            {
                strA += item.Key + "=" + item.Value + "&";
            }
            strA += "key=" + _key;

            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] md5Byte = md5.ComputeHash(System.Text.Encoding.Default.GetBytes(strA));
            var md5str = BitConverter.ToString(md5Byte).Replace("-", "");
            return md5str;
        }

        /// <summary>
        /// 购买购买模式
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ResultModel GetVipModels()
        {
            ResultModel result = new ResultModel();
            try
            {
                var list = _baseService.GetList<T_VipModel>(i => i.StateCode == "Enable", i => i.Asc(o => o.Money));
                result.result = (int)MsgType.success;
                result.type = MsgType.success.ToString();
                result.code = "200";
                result.data = list;
                result.msg = "获取数据成功";
            }
            catch (Exception ex)
            {
                result.msg = ex.Message;
                result.code = "500";
                log.Error(ex, ex.Message);
            }
            return result;
        }
        /// <summary>
        ///支付回调
        /// </summary>
        /// <param name="payId"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        [HttpPost]
        public ResultModel PayCallback(int payId, int userId, bool isCancel = false)
        {
            ResultModel result = new ResultModel();
            try
            {
                _userService.UpdateBuy(payId, userId, isCancel);

                result.result = (int)MsgType.success;
                result.type = MsgType.success.ToString();
                result.code = "200";
                result.msg = isCancel ? "支付取消" : "支付成功";
            }
            catch (Exception ex)
            {
                result.msg = ex.Message;
                result.code = "500";
                log.Error(ex, ex.Message);
            }
            return result;
        }
    }
}